<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>相声师承关系</title>
    <script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
    <script src="./js/go-2.1.31.js"></script>
    <style type="text/css">
      #myOverviewDiv {
        position: absolute;
        width: 200px;
        height: 100px;
        top: 10px;
        left: 10px;
        background-color: #f2f2f2;
        z-index: 300; /* make sure its in front */
        border: solid 1px #7986cb;
      }
    </style>
  </head>

  <body>
    <div id="myDiagramDiv" style="background-color: #f2f2f2; border: solid 1px black; width: 100%; height: 700px"></div>
    <div id="myOverviewDiv"></div>
    <input type="search" id="mySearch" onkeypress="if (event.keyCode === 13) searchDiagram()" />
    <button onclick="searchDiagram()">Search</button>
  </body>
  <script>
    var $Gm = go.GraphObject.make

    var myDiagram = $Gm(
      go.Diagram,
      'myDiagramDiv', // the DIV HTML element
      {
        // Put the diagram contents at the top center of the viewport
        initialDocumentSpot: go.Spot.Top,
        initialViewportSpot: go.Spot.Top,
        // OR: Scroll to show a particular node, once the layout has determined where that node is
        // "InitialLayoutCompleted": function(e) {
        //  var node = e.diagram.findNodeForKey(28);
        //  if (node !== null) e.diagram.commandHandler.scrollToPart(node);
        // },
        layout: $Gm(
          go.TreeLayout, // use a TreeLayout to position all of the nodes
          {
            isOngoing: false, // don't relayout when expanding/collapsing panels
            treeStyle: go.TreeLayout.StyleLastParents,
            // properties for most of the tree:
            angle: 90,
            layerSpacing: 80,
            // properties for the "last parents":
            alternateAngle: 0,
            alternateAlignment: go.TreeLayout.AlignmentStart,
            alternateNodeIndent: 15,
            alternateNodeIndentPastParent: 1,
            alternateNodeSpacing: 15,
            alternateLayerSpacing: 40,
            alternateLayerSpacingParentOverlap: 1,
            alternatePortSpot: new go.Spot(0.001, 1, 20, 0),
            alternateChildPortSpot: go.Spot.Left,
          }
        ),
      }
    )
    var mt8 = new go.Margin(8, 0, 0, 0)
    var mr8 = new go.Margin(0, 8, 0, 0)
    var ml8 = new go.Margin(0, 0, 0, 8)
    var roundedRectangleParams = {
      parameter1: 2, // set the rounded corner
      spot1: go.Spot.TopLeft,
      spot2: go.Spot.BottomRight, // make content go all the way to inside edges of rounded corners
    }
    function textStyle(field) {
      return [
        {
          font: '12px Roboto, sans-serif',
          stroke: 'rgba(0, 0, 0, .60)',
          visible: false, // only show textblocks when there is corresponding data for them
        },
        new go.Binding('visible', field, function (val) {
          return val !== undefined
        }),
      ]
    }

    // 我们早先定义的模板
    myDiagram.nodeTemplate = $Gm(
      go.Node,
      'Auto',
      {
        locationSpot: go.Spot.Top,
        isShadowed: true,
        shadowBlur: 1,
        shadowOffset: new go.Point(0, 1),
        shadowColor: 'rgba(0, 0, 0, .14)',
        // selection adornment to match shape of nodes
        selectionAdornmentTemplate: $Gm(go.Adornment, 'Auto', $Gm(go.Shape, 'RoundedRectangle', roundedRectangleParams, { fill: null, stroke: '#7986cb', strokeWidth: 3 }), $Gm(go.Placeholder)), // end Adornment
      },
      $Gm(
        go.Shape,
        'RoundedRectangle',
        roundedRectangleParams,
        { name: 'SHAPE', fill: '#ffffff', strokeWidth: 0 },
        // gold if highlighted, white otherwise
        new go.Binding('fill', 'isHighlighted', function (h) {
          return h ? 'gold' : '#ffffff'
        }).ofObject()
      ),
      $Gm(
        go.Panel,
        'Vertical',
        $Gm(
          go.Panel,
          'Horizontal',
          { margin: 8 },
          $Gm(
            go.Picture, // flag image, only visible if a nation is specified
            { margin: mr8, visible: false, desiredSize: new go.Size(45, 60) },
            new go.Binding('source', 'imgsrc'),
            new go.Binding('visible', 'imgsrc', function (nat) {
              return nat !== undefined
            })
          ),
          $Gm(
            go.Panel,
            'Table',
            $Gm(
              go.TextBlock,
              {
                row: 0,
                alignment: go.Spot.Left,
                font: '16px Roboto, sans-serif',
                stroke: 'rgba(0, 0, 0, .87)',
                maxSize: new go.Size(160, NaN),
              },
              new go.Binding('text', 'key')
            ),
            $Gm(
              go.TextBlock,
              textStyle('stageName'),
              {
                row: 1,
                alignment: go.Spot.Left,
                maxSize: new go.Size(160, NaN),
              },
              // new go.Binding('text', 'stageName')
              new go.Binding('text', 'stageName')
            ),
            $Gm('PanelExpanderButton', 'INFO', { row: 0, column: 1, rowSpan: 2, margin: ml8 })
          )
        ),
        $Gm(
          go.Shape,
          'LineH',
          {
            stroke: 'rgba(0, 0, 0, .60)',
            strokeWidth: 1,
            height: 1,
            stretch: go.GraphObject.Horizontal,
          },
          new go.Binding('visible').ofObject('INFO') // only visible when info is expanded
        ),
        $Gm(
          go.Panel,
          'Vertical',
          {
            name: 'INFO', // identify to the PanelExpanderButton
            stretch: go.GraphObject.Horizontal, // take up whole available width
            margin: 8,
            defaultAlignment: go.Spot.Left, // thus no need to specify alignment on each element
          },
          $Gm(
            go.TextBlock,
            textStyle('bdd'),
            new go.Binding('text', 'bdd', function (r) {
              if (r !== null) {
                return '生卒: ' + r
              }
              return ''
            })
          ),
          $Gm(
            go.TextBlock,
            textStyle('remark'),
            new go.Binding('margin', 'bdd', function (head) {
              return mt8
            }), // some space above if there is also a headOf value
            new go.Binding('text', 'remark', function (r) {
              if (r !== null) {
                return '备注: ' + r
              }
              return ''
            })
          )
        )
      )
    )

    function searchDiagram() {
      // called by button
      var input = document.getElementById('mySearch')
      if (!input) return
      myDiagram.focus()

      myDiagram.startTransaction('highlight search')

      if (input.value) {
        // search four different data properties for the string, any of which may match for success
        // create a case insensitive RegExp from what the user typed
        var regex = new RegExp(input.value, 'i')
        var results = myDiagram.findNodesByExample({ key: regex }, { stageName: regex }, { remark: regex }, { headOf: regex })
        myDiagram.highlightCollection(results)
        // try to center the diagram at the first node that was found
        if (results.count > 0) myDiagram.centerRect(results.first().actualBounds)
      } else {
        // empty string only clears highlighteds collection
        myDiagram.clearHighlighteds()
      }

      myDiagram.commitTransaction('highlight search')
    }

    // 定义一个直角路由形式的连线模板, 去掉箭头
    myDiagram.linkTemplate = $Gm(go.Link, { routing: go.Link.Orthogonal, corner: 5 }, $Gm(go.Shape, { strokeWidth: 3, stroke: '#555' })) // the link shape
    var model = $Gm(go.TreeModel)
    $('#myDiagramDiv').css('height', $(window).height() - 45 + 'px')

    $.ajax({
      type: 'GET',
      dataType: 'json',
      url: './data/tree.json',
      success: function (result) {
        model.nodeDataArray = result
        myDiagram.model = model
        // myDiagram.model = $(go.TreeModel, {
        //   // nodeParentKeyProperty: 'p', // this property refers to the parent node data
        //   nodeDataArray: result,
        // })

        // Overview
        myOverview = $Gm(
          go.Overview,
          'myOverviewDiv', // the HTML DIV element for the Overview
          { observed: myDiagram, contentAlignment: go.Spot.Center }
        )
      },
    })
  </script>
</html>
